#include "s_ds18b20.h"

#define DS18B20_CMD_SEARCH_ROM				0xF0
#define DS18B20_CMD_SKIP_ROM				0xCC
#define DS18B20_CMD_START_CONVERT_TEMP		0x44

#define DS18B20_DECIMAL_STEPS_12BIT			0.0625
#define DS18B20_DECIMAL_STEPS_11BIT			0.125
#define DS18B20_DECIMAL_STEPS_10BIT			0.25
#define DS18B20_DECIMAL_STEPS_9BIT			0.5

//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
signed char s_ds18b20_reset(ds18b20_t *ds)
{
	ds->ds18b20_out_init();
	ds->ds18b20_out_high();
	ds->ds18b20_delay_us(10);
	ds->ds18b20_out_low();
	ds->ds18b20_delay_us(500);
	// ds->ds18b20_out_high();();
	return 0;
}

signed char s_ds18b20_release_line(ds18b20_t *ds)
{
	ds->ds18b20_out_high();
	ds->ds18b20_out_init();
	
	ds->ds18b20_delay_us(10);

	return 0;
}

signed char s_ds18b20_init(ds18b20_t *ds)
{
	signed char bit;

	s_ds18b20_reset(ds);
	ds->ds18b20_in_init();
	ds->ds18b20_delay_us(70);

	bit = ds->ds18b20_read();

	ds->ds18b20_delay_us(500);

	s_ds18b20_release_line(ds);

	return bit;
}

signed char s_ds18b20_write_byte(ds18b20_t *ds, unsigned char data)
{
	unsigned char i = 0;
	// ds->ds18b20_out_init();
	// ds->ds18b20_out_high();();
	// ds->ds18b20_delay_us(10);
	// delay_ms(1);
	for(; i < 8; i++) {
		ds->ds18b20_out_init();
		if(data & 0x01) {
			ds->ds18b20_out_low();
			ds->ds18b20_delay_us(2);
			ds->ds18b20_in_init();
			// ds->ds18b20_out_high();();
			ds->ds18b20_delay_us(55);
		} else {
			ds->ds18b20_out_low();
			ds->ds18b20_delay_us(70);
			ds->ds18b20_in_init();
			// ds->ds18b20_out_high();();
			ds->ds18b20_delay_us(5);
		}
		data >>= 1;
		
	}

	// ds->ds18b20_out_init();
	// ds->ds18b20_out_high();();

	// s_ds18b20_release_line();

	ds->ds18b20_out_high();
	ds->ds18b20_out_init();

	return 0;
}


signed char s_ds18b20_read_bit(ds18b20_t *ds)
{
	signed char bit = 0;

	
	ds->ds18b20_out_low();
	ds->ds18b20_out_init();
	ds->ds18b20_delay_us(2);

	ds->ds18b20_in_init();
	// ds->ds18b20_delay_us(5);
	bit = ds->ds18b20_read();

	
	ds->ds18b20_delay_us(70);

	// ds->ds18b20_out_init();
	// ds->ds18b20_out_high();();

	return bit;
}

unsigned char s_ds18b20_read_byte(ds18b20_t *ds)
{
	unsigned char data = 0, i = 0;

	// ds->ds18b20_in_init();

	for(; i < 8; i++) {
		data >>= 1;
		data |= (s_ds18b20_read_bit(ds) << 7);
	}

	// ds->ds18b20_out_init();
	return data;
}

static unsigned char s_ds18b20_get_crc(ds18b20_t *ds, unsigned char *addr, unsigned char len) {
	unsigned char crc = 0, inbyte, i, mix;
	
	while (len--) {
		inbyte = *addr++;
		for (i = 8; i; i--) {
			mix = (crc ^ inbyte) & 0x01;
			crc >>= 1;
			if (mix) {
				crc ^= 0x8C;
			}
			inbyte >>= 1;
		}
	}
	
	/* Return calculated CRC */
	return crc;
}


signed char s_ds18b20_get_temperature_single(ds18b20_t *ds, float *temperature)
{
	unsigned char i, resolution;
	unsigned char data[9];
	signed short temp;
	signed char digit, minus = 0;
	float decimal;
	unsigned short try = 0;
	
	// printf("state:%d\r\n", s_ds18b20_init());
	s_ds18b20_init(ds);

	s_ds18b20_write_byte(ds, DS18B20_CMD_SKIP_ROM);
	s_ds18b20_write_byte(ds, DS18B20_CMD_START_CONVERT_TEMP);

	ds->ds18b20_in_init();
	while(!ds->ds18b20_read() && try++ < 100) {
		delay_ms(2);
	}

	if(try >= 100) {
		// printf("ds18b20 init failed\r\n");
		return (-3);
	}

	// printf("convert finihsed\r\n");

	// printf("state:%d\r\n", s_ds18b20_init());
	s_ds18b20_init(ds);

	s_ds18b20_write_byte(ds, DS18B20_CMD_SKIP_ROM);
	s_ds18b20_write_byte(ds, 0xBE);

	for(i = 0; i < 9; i++) {
			data[i] = s_ds18b20_read_byte(ds);
			// printf("0x%02x,", data[i]);
	}
	// printf("\r\n");

	if(data[8] != s_ds18b20_get_crc(ds, data, 8)) {
		// printf("crc not passed\r\n");
		return (-1);
	}

	temp = data[0] | data[1] << 8;

	// printf("%d\r\n", temp);

	/* Check if temperature is negative */
	if (temp & 0x8000)
	{
		/* Two's complement, temperature is negative */
		temp = ~temp + 1;
		minus = 1;
	}

	
	/* Get sensor resolution */
	resolution = ((data[4] & 0x60) >> 5) + 9;

	
	/* Store temperature integer digits and decimal digits */
	digit = temp >> 4;
	digit |= ((temp >> 8) & 0x7) << 4;

	/* Store decimal digits */
	switch (resolution) 
	{
		case 9:
			decimal = (temp >> 3) & 0x01;
			decimal *= (float)DS18B20_DECIMAL_STEPS_9BIT;
		break;
		case 10:
			decimal = (temp >> 2) & 0x03;
			decimal *= (float)DS18B20_DECIMAL_STEPS_10BIT;
		 break;
		case 11: 
			decimal = (temp >> 1) & 0x07;
			decimal *= (float)DS18B20_DECIMAL_STEPS_11BIT;
		break;
		case 12: 
			decimal = temp & 0x0F;
			decimal *= (float)DS18B20_DECIMAL_STEPS_12BIT;
		 break;
		default: 
			decimal = 0xFF;
			digit = 0;
	}

	// printf("%d, %d\r\n", digit, resolution);

	if(decimal != 0xFF && digit != 0) {
		*temperature = digit + decimal;
		if (minus) {
			*temperature = 0 - *temperature;
		}
		// printf("%d\r\n", (int)temp);
	} else {
		return (-2);
	}

	return 0;
}

signed char s_ds18b20_get_temperature(ds18b20_t *ds, float *temp)
{
	unsigned char i = 3;
	while(i--) {
		if(!s_ds18b20_get_temperature_single(ds, temp)) {
			// break;
			return 0;
		}
	}

	return (-1);
}

// #include <stdio.h>

// signed char s_ds18b20_test(void)
// {
// 	float temp;
// 	signed char rslt;
// 	// while(1) {
// 	// 	if(!s_ds18b20_get_temperature(&temp)) {
// 	// 		printf("%d\r\n", (int)(temp * 1000));
// 	// 	}
		
// 	// 	delay_ms(1000);
// 	// }
// 	rslt = s_ds18b20_get_temperature(&temp);
// 	if(rslt == 0) {
// 		printf("%d\r\n", (int)(temp * 1000));
// 	} else {
// 		printf("rslt %d\r\n", rslt);	
// 	// delay_ms(1000);
// 	// }
	
// 	}
// }


